
package cz.czu.pef.DataModelling.data;

import java.util.*;
import java.util.logging.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import cz.czu.pef.DataModelling.*;
import cz.czu.pef.DataModelling.dao.*;

@Component(value="basicGardeningData")
@Transactional
@SuppressWarnings("unused")
public class BasicGardeningData
{
	Logger logger = Logger.getLogger(BasicGardeningData.class.getName());
	@Autowired AddressDao addressDao;
	@Autowired CompanyDao companyDao;
	@Autowired EmployeeDao employeeDao;
	@Autowired ExternalWorkerDao externalWorkerDao;
	@Autowired PersonDao personDao;
	@Autowired MachineryDao machineryDao;
	@Autowired MachineTypeDao machineTypeDao;
	@Autowired RoleTypeDao roleTypeDao;
	@Autowired TrainingTypeDao trainingTypeDao;
	@Autowired TrainingTypeForRoleTypeDao trainingTypeForRoleTypeDao;
	@Autowired MedicalExaminationTypeDao medicalExaminationTypeDao;
	@Autowired MedicalExaminationTypeForRoleTypeDao medicalExaminationTypeForRoleTypeDao;

	public long yearsToSeconds(long years)
	{
		return (long)((double)years * 365.2422 * 24 * 60 * 60);
	}

	public final String ROLETYPE_CODE_RIDIC_PROFI = "RIDIC_PROFI";
	public final String ROLETYPE_CODE_ZAHR_MISTR = "ZAHR_MISTR";
	public final String ROLETYPE_CODE_ZAHRADNIK = "ZAHRADNIK";
	public final String ROLETYPE_CODE_DELNIK = "DELNIK";
	public final String ROLETYPE_CODE_THP = "THP";

	public void fillBasicData() throws InstantiationException, IllegalAccessException
	{

		// ##############################################
		// ROLE TYPES
		// ##############################################
		RoleType roleRidicProfi;
		RoleType roleZahradnickyMistr;
		RoleType roleZahradnik;
		RoleType roleDelnik;
		RoleType roleThp;

		// ##############################################
		// TRAINING TYPES
		// ##############################################
		TrainingType training_BOZP;
		TrainingType training_PO;
		TrainingType training_pily;
		TrainingType training_plosiny;
		TrainingType training_strojnici;
		TrainingType training_ridici_normal;
		TrainingType training_zahr_mistri;
		TrainingType training_ridici_profi;
		TrainingType training_voziky;

		// ##############################################
		// MEDICAL EXAMINATION TYPES
		// ##############################################
		MedicalExaminationType medExam_Praktik; 
		MedicalExaminationType medExam_Ocni; 
		MedicalExaminationType medExam_Neurolog; 
		MedicalExaminationType medExam_Psycholog; 

		// ##############################################
		// ROLE TYPES
		// ##############################################
		roleRidicProfi = roleTypeDao.merge(new RoleType(ROLETYPE_CODE_RIDIC_PROFI, "Ridič profesionál", "Ridic z povolani"));
		roleZahradnickyMistr = roleTypeDao.merge(new RoleType(ROLETYPE_CODE_ZAHR_MISTR, "Zahradnický mistr", "Zahradnicky mistr"));
		roleZahradnik = roleTypeDao.merge(new RoleType(ROLETYPE_CODE_ZAHRADNIK, "Zahradník", "Zahradnik"));
		roleDelnik = roleTypeDao.merge(new RoleType(ROLETYPE_CODE_DELNIK, "Dělník", "Delnik"));
		roleThp = roleTypeDao.merge(new RoleType(ROLETYPE_CODE_THP, "Technicko-hospodářský pracovník", "Pracovník administrativy"));

		// ##############################################
		// TRAINING TYPES
		// ##############################################
		training_BOZP = trainingTypeDao.merge(new TrainingType("BOZP", "Bezpečnost a ochrana zdraví při práci", "Školení - Bezpečnost a ochrana zdraví při práci", null, yearsToSeconds(1)));
		training_PO = trainingTypeDao.merge(new TrainingType("PO", "Požární ochrana", "Školení - Požární ochrana", null, yearsToSeconds(1)));
		training_pily = trainingTypeDao.merge(new TrainingType("PILY", "Pily a křovinořezy", "Školení - Pily a křovinořezy", null, yearsToSeconds(1)));
		training_plosiny = trainingTypeDao.merge(new TrainingType("PLOSINY", "Plošiny", "Školení - Plošiny", "Průkaz obsluhy plošin", yearsToSeconds(2)));
		training_strojnici = trainingTypeDao.merge(new TrainingType("STROJNICI", "Strojníci", "Školení - Strojníci", "Strojnický průkaz", yearsToSeconds(1)));
		training_ridici_normal = trainingTypeDao.merge(new TrainingType("RIDICI_NORMAL", "Řidiči referenti", "Školení - Řidiči referenti", "Průkaz na referentká vozidla", yearsToSeconds(1)));
		training_zahr_mistri = trainingTypeDao.merge(new TrainingType("ZAHR_MISTRI", "Zahradničtí mistři", "Školení - Zahradničtí mistři", null, yearsToSeconds(3)));
		training_ridici_profi = trainingTypeDao.merge(new TrainingType("RIDICI_PROFI", "Řidiči z povolání", "Školení - Řidiči z povolání", "Profesní průkaz", yearsToSeconds(1)));
		training_voziky = trainingTypeDao.merge(new TrainingType("VOZIKY", "Vysokozdvižné vozíky", "Školení - Vysokozdvižné vozíky", "Průkaz obsluhy na vysokozdvižné vozíky", yearsToSeconds(2)));

		// TRAINING TYPES - roleRidicProfi
		roleRidicProfi.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_BOZP, yearsToSeconds(1))));
		roleRidicProfi.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_PO, yearsToSeconds(1))));
		roleRidicProfi.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_ridici_profi, yearsToSeconds(1))));

		// TRAINING TYPES - roleZahradnickyMistr
		roleZahradnickyMistr.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_BOZP, yearsToSeconds(1))));
		roleZahradnickyMistr.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_PO, yearsToSeconds(1))));
		roleZahradnickyMistr.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_ridici_normal, yearsToSeconds(1))));
		roleZahradnickyMistr.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_zahr_mistri, yearsToSeconds(1))));

		// TRAINING TYPES - roleZahradnik
		roleZahradnik.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_BOZP, yearsToSeconds(1))));
		roleZahradnik.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_PO, yearsToSeconds(1))));
		roleZahradnik.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_pily, yearsToSeconds(1))));

		// TRAINING TYPES - roleDelnik
		roleDelnik.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_BOZP, yearsToSeconds(1))));
		roleDelnik.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_PO, yearsToSeconds(1))));

		// TRAINING TYPES - roleThp
		roleThp.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_BOZP, yearsToSeconds(1))));
		roleThp.addTrainingTypeForRoleType(trainingTypeForRoleTypeDao.merge(new TrainingTypeForRoleType(training_PO, yearsToSeconds(1))));


		// ##############################################
		// MEDICAL EXAMINATION TYPES
		// ##############################################
		medExam_Praktik = medicalExaminationTypeDao.merge(new MedicalExaminationType("PRAKTIK", "Běžná prohlídka", "Prohlídka u obvodního lékaře")); 
		medExam_Ocni = medicalExaminationTypeDao.merge(new MedicalExaminationType("OCNI", "Oční vyšetření", "Vyšetření u očního lékaře")); 
		medExam_Neurolog = medicalExaminationTypeDao.merge(new MedicalExaminationType("NEURO", "Neurologické vyšetření",  "Vyšetření u neurologa")); 
		medExam_Psycholog = medicalExaminationTypeDao.merge(new MedicalExaminationType("PSYCHO", "Psychologické vyšetření", "Vyšetření u psychologa")); 

		// MEDICAL EXAMINATION TYPES - roleRidicProfi
		roleRidicProfi.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Praktik, yearsToSeconds(1))));
		roleRidicProfi.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Ocni, yearsToSeconds(1))));
		roleRidicProfi.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Neurolog, yearsToSeconds(0))));
		roleRidicProfi.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Psycholog, yearsToSeconds(0))));

		// MEDICAL EXAMINATION TYPES - roleZahradnickyMistr
		roleZahradnickyMistr.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Praktik, yearsToSeconds(1))));
		
		// MEDICAL EXAMINATION TYPES - roleZahradnik
		roleZahradnik.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Praktik, yearsToSeconds(1))));
		// MEDICAL EXAMINATION TYPES - roleDelnik
		roleDelnik.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Praktik, yearsToSeconds(1))));
		// MEDICAL EXAMINATION TYPES - roleThp
		roleThp.addMedicalExaminationTypeForRoleType(medicalExaminationTypeForRoleTypeDao.merge(new MedicalExaminationTypeForRoleType(medExam_Praktik, yearsToSeconds(3))));
	}

	public void fillPeopleAndCompanies() throws InstantiationException, IllegalAccessException
	{
		// ADRESA - Křižatky
		Address krizatky = addressDao.merge(new Address("Křižatky 46", "Králův Dvůr", "Czech Republic", "267 01"));

		// Rostislav Stříbrný
		Person rosta = new Person("Rostislav", "Stříbrný", krizatky);
		rosta = personDao.merge(rosta);
		Employee empStribrny = employeeDao.merge(new Employee(rosta));
		ExternalWorker extWorkerRosta = externalWorkerDao.merge(new ExternalWorker(rosta));
		rosta.setBirthDate(new Date());

		// Dagmar Stříbrná
		Employee empCermakova = employeeDao.merge(new Employee(new Person("Dagmar", "Stříbrná", krizatky)));
		empCermakova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_THP)));

		// Vilík Stříbrný
		Person vilik = personDao.merge(new Person("Vilém", "Stříbrný", krizatky));

		// Other JENA workers
		Employee empKahlerova = employeeDao.merge(new Employee(new Person("Barbora", "Kahlerová")));
		empKahlerova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_THP)));

		Employee empSimkova = employeeDao.merge(new Employee(new Person("Lucie", "Šimková")));
		empSimkova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_THP)));
		empSimkova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_ZAHR_MISTR)));

		Employee empVecer = employeeDao.merge(new Employee(new Person("Aleš", "Večeř")));
		empVecer.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_RIDIC_PROFI)));

		Employee empBujnak = employeeDao.merge(new Employee(new Person("Dan", "Bujňák")));
		empBujnak.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_ZAHRADNIK)));

		Employee empPlaz = employeeDao.merge(new Employee(new Person("Miroslav", "Plaz")));
		empPlaz.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_ZAHRADNIK)));

		Employee empSedlackova = employeeDao.merge(new Employee(new Person("Lucie", "Sedláčková")));
		empSedlackova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_THP)));

		Employee empKormundova = employeeDao.merge(new Employee(new Person("Pavla", "Kormundová")));
		empKormundova.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_THP)));

		Employee empPrasil = employeeDao.merge(new Employee(new Person("Jaroslav", "Prášil")));
		empPrasil.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_ZAHRADNIK)));

		Employee empPastva = employeeDao.merge(new Employee(new Person("Josef", "Pastva")));
		empPastva.addRole(new Role(roleTypeDao.findByAttributeUniqueResult("code", ROLETYPE_CODE_ZAHRADNIK)));


		// JENA company
		Address jenaAddress = addressDao.merge(new Address("Letna XYZ", "Praha", "Czech Republic", "140 00"));
		Company jenaCompany = companyDao.merge(new Company("JENA", "ICO 1"));
		jenaCompany.setBaseAddress(jenaAddress);

		jenaCompany.hireEmployee(empCermakova);
		jenaCompany.hireEmployee(empKahlerova);
		jenaCompany.hireEmployee(empSimkova);
		jenaCompany.hireEmployee(empVecer);
		jenaCompany.hireEmployee(empVecer);
		jenaCompany.hireEmployee(empPlaz);
		jenaCompany.hireEmployee(empSedlackova);
		jenaCompany.hireEmployee(empKormundova);
		jenaCompany.hireEmployee(empPrasil);
		jenaCompany.hireEmployee(empPastva);
		jenaCompany.hireExternalWorker(extWorkerRosta);
		
		// Other NESS colleagues
		Employee nessEmployee2 = employeeDao.merge(new Employee(new Person("Petr", "Bažant", null)));
		Employee nessEmployee3 = employeeDao.merge(new Employee(new Person("Tomáš", "Boch", null)));
		Employee nessEmployee4 = employeeDao.merge(new Employee(new Person("Ivan", "Oravec", null)));
		Employee nessEmployee5 = employeeDao.merge(new Employee(new Person("René", "Trbušek", null)));

		// NESS company
		Company nessCompany = companyDao.merge(new Company("NESS", "ICO 2"));
		nessCompany.hireEmployee(empStribrny);
		nessCompany.hireEmployee(nessEmployee2);
		nessCompany.hireEmployee(nessEmployee3);
		nessCompany.hireEmployee(nessEmployee4);
		nessCompany.hireEmployee(nessEmployee5);


		// ADD SOME random TRAININGS...
		//TrainingType bozpTraningType = (TrainingType)trainingTypeDao.getEntityManager().createNamedQuery("findTrainingTypeByCode").setParameter("code", "BOZP").getSingleResult();
		TrainingType bozpTraningType = trainingTypeDao.findByAttributeUniqueResult("code", "BOZP");
		if (bozpTraningType == null)
			throw new RuntimeException("bozpTraningType trainingType does not exists!");
		TrainingType poTraningType = trainingTypeDao.findByAttributeUniqueResult("code", "PO");
		if (poTraningType == null)
			throw new RuntimeException("poTraningType trainingType does not exists!");

		@SuppressWarnings("unchecked")
		List<Employee> emps = trainingTypeDao.getEntityManager().createQuery("select emp from Employee as emp").getResultList();
		for (Employee emp: emps)
		{
			Calendar r1 = Calendar.getInstance();
			r1.add(Calendar.MONTH, -(new Random()).nextInt(12));

			Calendar r2 = Calendar.getInstance();
			r2.add(Calendar.MONTH, -(new Random()).nextInt(12));

			emp.addTraining(new Training(bozpTraningType, null, r1.getTime()));
			emp.addTraining(new Training(poTraningType, null, r2.getTime()));
		}
	}

	public void fillMachineries() throws InstantiationException, IllegalAccessException
	{
		MachineType mtOsobniAuto = machineTypeDao.merge(new MachineType("Osobní auta", "Osobní automobily"));
		MachineType mtUzitkoveAuto = machineTypeDao.merge(new MachineType("Užitková auta", "Užitkové automobily"));
		MachineType mtNakladniAuto = machineTypeDao.merge(new MachineType("Nákladní auta", "Nákladní automobil"));
		MachineType mtPrivesy = machineTypeDao.merge(new MachineType("Privesy", "Přívěsy"));
		MachineType mtTraktory = machineTypeDao.merge(new MachineType("Traktory", "Traktory"));
		MachineType mtStavebniStroje = machineTypeDao.merge(new MachineType("Stavební stroje", "Stavební stroje"));
		MachineType mtZemedelskeStroje = machineTypeDao.merge(new MachineType("Zemědělské stroje", "Zemědělské stroje"));

		MachineType mtPily = machineTypeDao.merge(new MachineType("Pily", "Pily"));
		MachineType mtKrovinorezy = machineTypeDao.merge(new MachineType("Křovinořezy", "Křovinořezy"));
		MachineType mtFukary = machineTypeDao.merge(new MachineType("Fukary", "Fukary"));
		MachineType mtPlosiny = machineTypeDao.merge(new MachineType("Plošiny", "Plošiny"));
		MachineType mtVysokoVoziky = machineTypeDao.merge(new MachineType("Vysokozdvižné vozíky", "Vysokozdvižné vozíky"));
		MachineType mtSekacky = machineTypeDao.merge(new MachineType("Sekačky", "Sekačky"));

		MachineType genTypes[] = new MachineType[]{mtOsobniAuto, mtUzitkoveAuto, mtNakladniAuto, mtNakladniAuto, mtPrivesy, mtTraktory, mtStavebniStroje, mtZemedelskeStroje,
				mtPily, mtKrovinorezy, mtFukary, mtPlosiny, mtVysokoVoziky, mtSekacky
				};

		Company jenaCompany = companyDao.findByAttributeUniqueResult("name", "JENA");
		if (jenaCompany == null)
			throw new RuntimeException("JENA company does not exists!");

		// JENA MACHINERY - RANDOM
		for (int i=0; i<100 ; i++)
		{
			int randomType = (new Random()).nextInt(genTypes.length);
			String serialNo = "JENA-SERIAL-NO-" + i;
			Machinery machTmp = machineryDao.findByAttributeUniqueResult("machinerySerialNo", serialNo);
			if (machTmp == null)
			{
				logger.log(Level.FINE, "Creating new Machinery with serialNo = " + serialNo);
				machineryDao.merge(new Machinery(serialNo, genTypes[randomType], null, jenaCompany));
			}
			else
			{
				System.out.println("Machinery with serialNo = " + serialNo + " already exists.");
			}
		}
	}

	public void getSomeData() throws InstantiationException, IllegalAccessException
	{
		List<Person> people = personDao.findAll();
		List<Company> companies = companyDao.findAll();
		if (companies != null && companies.get(0) != null)
		{
			System.out.println("First company: " + companies.get(0).toString());
		}
	}
}
